package com.swak.reactivex.transport;

import java.net.SocketAddress;

import org.springframework.util.Assert;

import com.swak.Constants;
import com.swak.exception.RemotingException;
import com.swak.registry.URL;
import com.swak.utils.Ints;

import lombok.Getter;

/**
 * 端点
 * 
 * @author lifeng
 */
public abstract class Endpoint implements ChannelHandler {

	protected volatile boolean closing;
	protected volatile boolean closed;
	protected volatile boolean started;

	@Getter
	protected final URL url;
	@Getter
	protected final ChannelHandler handler;
	@Getter
	private int connectionTimeout;
	@Getter
	private int writeTimeout;
	@Getter
	private int heartbeat;
	@Getter
	private int idleTimeout;

	public Endpoint(URL url, ChannelHandler handler) {
		Assert.isTrue(url != null, "url == null");
		Assert.isTrue(handler != null, "handler == null");
		this.url = url;
		this.handler = handler;
		this.connectionTimeout = url.getIntParameter(Constants.Connection_Timeout,
				Constants.Default_Connection_Timeout);
		this.writeTimeout = url.getIntParameter(Constants.Timeout, Constants.Default_Timeout);
		this.heartbeat = url.getIntParameter(Constants.Heartbeat, Constants.Default_Heartbeat);
		int idleTimeout = url.getIntParameter(Constants.Heartbeat_Timeout, this.heartbeat * 3);
		this.idleTimeout = Ints.min(idleTimeout, this.heartbeat * 2);
	}

	public URL url() {
		return this.url;
	}

	public void close() {
		closed = true;
	}

	public void close(int timeout) {
		close();
	}

	public void startClose() {
		if (isClosed()) {
			return;
		}
		closing = true;
		started = false;
	}

	public boolean isClosed() {
		return closed;
	}

	public boolean isClosing() {
		return closing && !closed;
	}

	@Override
	public void connected(Channel channel) throws RemotingException {
		if (closed) {
			return;
		}
		handler.connected(channel);
	}

	@Override
	public void disconnected(Channel channel) throws RemotingException {
		handler.disconnected(channel);
	}

	@Override
	public void sent(Channel channel, Object message) throws RemotingException {
		if (closed) {
			return;
		}
		handler.sent(channel, message);
	}

	@Override
	public void received(Channel channel, Object message) throws RemotingException {
		if (closed) {
			return;
		}
		handler.received(channel, message);
	}

	@Override
	public void caught(Channel channel, Throwable exception) throws RemotingException {
		handler.caught(channel, exception);
	}

	public abstract SocketAddress localAddress();

	public abstract SocketAddress remoteAddress();

	public abstract void send(Object message, boolean sent) throws RemotingException;
}